package com.learn.springboot.config.shiro;

import com.learn.springboot.util.PasswordHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @author dyz
 * @date 2020/6/13 17:36
 */
@Slf4j
@Configuration
public class ShiroConfig {

    /**
     * shiro过滤器工厂bean
     *
     * @param securityManager 安全管理器
     * @return {@link ShiroFilterFactoryBean}
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        log.info("getShiroFilterFactoryBean ...");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        /*
         * Shiro通过一系列filter来控制访问权限，并在它的内部为我们预先定义了多个过滤器，我们可以直接通过字符串配置这些过滤器。
         *
         * 常用的过滤器如下：
         *
         * authc：所有已登陆用户可访问
         *
         * roles：有指定角色的用户可访问，通过[ ]指定具体角色，这里的角色名称与数据库中配置一致
         *
         * perms：有指定权限的用户可访问，通过[ ]指定具体权限，这里的权限名称与数据库中配置一致
         *
         * anon：所有用户可访问，通常作为指定页面的静态资源时使用
         */
        Map<String, String> filterChainDefinitionMap = new HashMap<>(16);
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthc");
        shiroFilterFactoryBean.setSuccessUrl("/home/index");

        filterChainDefinitionMap.put("/*", "anon");
        filterChainDefinitionMap.put("/authc/index", "authc");
        filterChainDefinitionMap.put("/authc/admin", "roles[admin]");
        filterChainDefinitionMap.put("/authc/renewable", "perms[Create,Update]");
        filterChainDefinitionMap.put("/authc/removable", "perms[Delete]");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 默认的web安全管理器
     *
     * @param shiroRealm shiro领域
     * @return {@link DefaultWebSecurityManager}
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("shiroRealm") EnchiladasShirlRealm shiroRealm) {
        log.info("getDefaultWebSecurityManager ...");
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(shiroRealm);
        return securityManager;
    }

    /**
     * 创建 Realm
     *
     * @return {@link EnchiladasShirlRealm}
     */
    @Bean(name = "shiroRealm")
    public EnchiladasShirlRealm shiroRealm() {
        log.info("shiroRealm ...");
        EnchiladasShirlRealm shiroRealm = new EnchiladasShirlRealm();
        // 原来在这里 : 认证的时候我们需要提供相同的散列算法
        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return shiroRealm;
    }

    /**
     * 散列凭证匹配器
     *
     * @return {@link HashedCredentialsMatcher}
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 散列算法
        hashedCredentialsMatcher.setHashAlgorithmName(PasswordHelper.ALGORITHM_NAME);
        // 散列次数
        hashedCredentialsMatcher.setHashIterations(PasswordHelper.HASH_ITERATIONS);
        return hashedCredentialsMatcher;
    }

    /**
     * 密码助手
     *
     * @return {@link PasswordHelper}
     */
    @Bean
    public PasswordHelper passwordHelper() {
        return new PasswordHelper();
    }
}
